#pragma once
#include <iostream>
#include <pthread.h>
#include <queue>
#include "Task.hpp"
#include "Log.hpp"

#define NUM 6

class ThreadPool
{
private:
    int num;//线程个数
    bool stop;//是否终止
    std::queue<Task> task_queue;//任务队列
    pthread_mutex_t lock;
    pthread_cond_t cond;
    static ThreadPool* single_instance;

    ThreadPool(int _num = NUM):num(_num),stop(false)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
    }
    ThreadPool(const ThreadPool& t) = delete;
public:
    static ThreadPool* GetInstance()
    {
        static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
        if(single_instance == nullptr)
        {
            pthread_mutex_lock(&_mutex);
            if(single_instance == nullptr)
            {
                single_instance = new ThreadPool();
                single_instance->InitThreadPool();
            }
            pthread_mutex_unlock(&_mutex);
        }
        return single_instance;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
    bool IsStop()
    {
        return stop;
    }
    bool TaskQueueIsEmpty()
    {
        return task_queue.empty();
    }
    void Lock()
    {
        pthread_mutex_lock(&lock);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&lock);
    }
    void ThreadWait()
    {
        pthread_cond_wait(&cond, &lock);
    }
    void ThreadWakeUp()
    {
        pthread_cond_signal(&cond);
        //pthread_cond_broadcast(&cond);
    }
    static void* ThreadRoutine(void *args)//线程历程
    {
        ThreadPool* tp = (ThreadPool*)args;
        
        while(true)
        {
            Task t;//输出型参数
            tp->Lock();
            while(tp->TaskQueueIsEmpty())//唤醒后再次检测，避免伪唤醒
            {
                tp->ThreadWait();//醒来的时候一定占有互斥锁
            }
            tp->PopTask(t);
            tp->UnLock();

            t.ProcessOn();//处理任务
        }
    }
    bool InitThreadPool()
    {
        for(int i=0; i<num; i++)
        {
            pthread_t tid;
            if(0 != pthread_create(&tid, nullptr, ThreadRoutine, (void*)this))
            {
                LOG(FATAL, "create thread_pool error");
                return false;
            }
        }
        LOG(INFO, "create thread_pool success");
        return true;
    }
    void PushTask(const Task& task)//in
    {
        Lock();
        task_queue.push(task);
        UnLock();
        ThreadWakeUp();
    }
    void PopTask(Task &task)//out,输出型参数取出任务
    {
        task = task_queue.front();
        task_queue.pop();
    }

};
ThreadPool* ThreadPool::single_instance = nullptr;
